#ifndef INTERFACE_MENU_H
#define INTERFACE_MENU_H


#include "Engine/Synaptic/Misc.h"
#include <string>
#include "SDL.h"
#include <vector>

namespace Interface {

class Menu {
  public:
    // Base for a menu entry
    class MenuEntry {
  friend class Menu;

      protected:
    	Misc::Frame frame; // Entry frame on screen
    	bool entryActive; 
    	bool entryHidden; 
    	std::string entryName; 

      public:
    	MenuEntry(const Misc::Frame & frame, std::string entryName); 
    	virtual void haveFocus(bool focused); // Menu entry have focus.
    	virtual void select() = 0; // Menu entry was selected
    	virtual ~MenuEntry(); 
    	inline virtual MenuEntry & hidden(bool isHidden); 
    	inline virtual bool hidden(); 
    	inline virtual MenuEntry & active(bool isActive); 
    	inline virtual bool active(); 
    };
    
    struct MenuResponse {
    	Sint16 index; 
    	MenuEntry * entryPointer; // Pointer to the entry that was selected
    	std::string entryName; 
    };
    
    typedef std::vector<MenuEntry *> EntryList;

	Menu(const Misc::Frame & frame, Uint16 size); 
	virtual ~Menu(); 
	virtual void focusNext(); //Focus an adjacent entry
	virtual void focusPrevious(); //Focus an adjacent entry
	inline virtual Menu & focusAt(Uint16 index); // Focus an specific position
	inline virtual MenuResponse select(); // Select the current focused selection
	inline MenuEntry *& operator[](Uint16 index); 
	inline virtual Menu & hidden(bool isHidden); 
	inline virtual bool hidden(); 
	inline virtual Menu & active(bool isActive); 
	inline virtual bool active(); 
	inline Uint16 size(); 

  protected:
	Misc::Frame frame; // Frame of menu and sensible area

  private:
	EntryList entries; 
	Sint16 focus; 

  protected:
	bool menuActive; 
	bool menuHidden; 
};
inline Menu::MenuEntry & Menu::MenuEntry::hidden(bool isHidden) {
	entryHidden = isHidden;
	return *this;
}

inline bool Menu::MenuEntry::hidden() {
	return entryHidden;
}

inline Menu::MenuEntry & Menu::MenuEntry::active(bool isActive) {
	entryActive = isActive;
	return *this;
}

inline bool Menu::MenuEntry::active() {
	return entryActive;
}

// Focus an specific position
inline Menu & Menu::focusAt(Uint16 index) {
	if (menuHidden || !menuActive || (entries[index] != NULL && entries[index]->hidden()) || (entries[index] != NULL && !entries[index]->active())) return *this;
	if (focus >= 0 && focus < (Sint16)entries.size() && entries[focus] != NULL)
	  entries[focus]->haveFocus(false);
	
	focus = index;
	
	if (focus >= 0 && focus < (Sint16)entries.size() && entries[focus] != NULL)
	  entries[focus]->haveFocus(true);
  
	return *this;
}

// Select the current focused selection
inline Menu::MenuResponse Menu::select() {
	if (
		!menuHidden &&
		menuActive &&
		
		entries[focus] != NULL &&
		
		!entries[focus]->hidden() &&
		entries[focus]->active()
		) entries[focus]->select();
	MenuResponse response = { focus, entries[focus], entries[focus]->entryName };
	return response;
}

inline Menu::MenuEntry *& Menu::operator[](Uint16 index) {
	return entries[index];
}

inline Menu & Menu::hidden(bool isHidden) {
	for (Uint16 i = 0; i < entries.size(); i++) {
		if (entries[i]) entries[i]->hidden(isHidden);
	}
	menuHidden = isHidden;
	return *this;
}

inline bool Menu::hidden() {
	return menuHidden;
}

inline Menu & Menu::active(bool isActive) {
	for (Uint16 i = 0; i < entries.size(); i++) {
		if (entries[i]) entries[i]->active(isActive);
	}
	menuActive = isActive;
	return *this;
	
}

inline bool Menu::active() {
	return menuActive;
}

inline Uint16 Menu::size() {
	return entries.size();
}


} // namespace Interface
#endif
